using System;
using NUnit.Framework;
using ValidationFramework.Reflection;
#if (!SILVERLIGHT && !WindowsCE)
using ValidationFramework.Web.ASP;
#endif

namespace ValidationFramework.Tests
{
    public class RangeRuleTest
    {

        const int expectedMinimum = 1;
        const int expectedMaximum = 3;
        const string expectedErrorMessage = "expectedErrorMessage";
        const string expectedRuleSet = "EXPECTEDRULESET";
 
        
        [TestFixture]
        public class Construction
        {
            [Test]
            public void Simple1()
            {
                var rule = new RangeRule<int>(expectedErrorMessage, false, expectedMinimum, expectedMaximum, true, false);
                Assert.AreEqual(expectedMinimum, rule.Minimum);
                Assert.AreEqual(expectedMinimum, rule.Minimum);
                Assert.AreEqual(expectedErrorMessage, rule.ErrorMessage);
                Assert.IsFalse(rule.UseErrorMessageProvider);
                Assert.IsFalse(rule.EqualsMaximumIsValid);
                Assert.IsTrue(rule.EqualsMinimumIsValid);
            }


            [Test]
            public void Simple2()
            {
                var rule = new RangeRule<int>(expectedErrorMessage, expectedMinimum, expectedMaximum);
                Assert.AreEqual(expectedMinimum, rule.Minimum);
                Assert.AreEqual(expectedMinimum, rule.Minimum);
                Assert.AreEqual(expectedErrorMessage, rule.ErrorMessage);
                Assert.IsFalse(rule.UseErrorMessageProvider);
                Assert.IsTrue(rule.EqualsMaximumIsValid);
                Assert.IsTrue(rule.EqualsMinimumIsValid);
            }


            [Test]
            public void Simple3()
            {
                var rule = new RangeRule<int>(expectedMinimum, expectedMaximum);
                Assert.AreEqual(expectedMinimum, rule.Minimum);
                Assert.AreEqual(expectedMinimum, rule.Minimum);
                Assert.IsNull(rule.ErrorMessage);
                Assert.IsFalse(rule.UseErrorMessageProvider);
                Assert.IsTrue(rule.EqualsMaximumIsValid);
                Assert.IsTrue(rule.EqualsMinimumIsValid);
            }
        }


        [TestFixture]
        public class IsEquivalent
        {
            [Test]
            public void Simple()
            {
                var rule1 = new RangeRule<int>(null, false, 1, 5, true, true);
                var rule2 = new RangeRule<int>(null, false, 1, 5, true, true);
                Assert.IsTrue(rule1.IsEquivalent(rule2));
                rule1 = new RangeRule<int>(null, false, 1, 5, true, true);
                rule2 = new RangeRule<int>(null, false, 1, 5, true, true);
                Assert.IsTrue(rule1.IsEquivalent(rule2));
                rule1 = new RangeRule<int>(null, false, 1, 5, false, false);
                rule2 = new RangeRule<int>(null, false, 1, 5, false, false);
                Assert.IsTrue(rule1.IsEquivalent(rule2));


                rule1 = new RangeRule<int>(null, false, 1, 5, false, false);
                rule2 = new RangeRule<int>(null, false, 1, 5, true, false);
                Assert.IsFalse(rule1.IsEquivalent(rule2));


                rule1 = new RangeRule<int>(null, false, 1, 5, false, false);
                rule2 = new RangeRule<int>(null, false, 1, 3, false, false);
                Assert.IsFalse(rule1.IsEquivalent(rule2));

                var stringRule1 = new RangeRule<string>(null, false, "a", "a", false, false);
                var stringRule2 = new RangeRule<string>(null, false, "a", null, false, false);
                Assert.IsFalse(stringRule1.IsEquivalent(stringRule2));

                stringRule1 = new RangeRule<string>(null, false, "a", null, false, false);
                stringRule2 = new RangeRule<string>(null, false, "a", "a", false, false);
                Assert.IsFalse(stringRule1.IsEquivalent(stringRule2));

                stringRule1 = new RangeRule<string>(null, false, "a", null, false, false);
                stringRule2 = new RangeRule<string>(null, false, "a", null, false, false);
                Assert.IsTrue(stringRule1.IsEquivalent(stringRule2));


            }
        }


        [TestFixture]
        public class Validate
        {
            [Test]
            public void Nullable()
            {
                var rule = new RangeRule<int>(null, false, expectedMinimum, expectedMaximum, true, true);
                rule.CheckType(new MockInfoDescriptor(typeof(int?).TypeHandle, "foo"));

                Assert.IsNull(rule.Validate(null, null, null, null));
                Assert.IsNotNull(rule.Validate(null, 0, null, null));
                Assert.IsNull(rule.Validate(null, 1, null, null));
                Assert.IsNull(rule.Validate(null, 2, null, null));
                Assert.IsNull(rule.Validate(null, 3, null, null));
                Assert.IsNotNull(rule.Validate(null, 4, null, null));
            }


            [Test]
            public void NullableExclusive()
            {
                var rule = new RangeRule<int>(null, false, expectedMinimum, expectedMaximum, false, false);
                rule.CheckType(new MockInfoDescriptor(typeof(int?).TypeHandle, "foo"));

                Assert.IsNull(rule.Validate(null, null, null, null));
                Assert.IsNotNull(rule.Validate(null, 0, null, null));
                Assert.IsNotNull(rule.Validate(null, 1, null, null));
                Assert.IsNull(rule.Validate(null, 2, null, null));
                Assert.IsNotNull(rule.Validate(null, 3, null, null));
                Assert.IsNotNull(rule.Validate(null, 4, null, null));
            }

            [Test]
            public void NotNullable()
            {
                var rule = new RangeRule<int>(null, false, expectedMinimum, expectedMaximum, true, true);
                rule.CheckType(new MockInfoDescriptor(TypePointers.IntTypeHandle, "foo"));
                Assert.IsNotNull(rule.Validate(null, 0, null, null));
                Assert.IsNull(rule.Validate(null, 1, null, null));
                Assert.IsNull(rule.Validate(null, 2, null, null));
                Assert.IsNull(rule.Validate(null, 3, null, null));
                Assert.IsNotNull(rule.Validate(null, 4, null, null));
            }


            [Test]
            public void NotNullableExclusive()
            {
                var rule = new RangeRule<int>(null, false, expectedMinimum, expectedMaximum, false, false);
                rule.CheckType(new MockInfoDescriptor(TypePointers.IntTypeHandle, "foo"));
                Assert.IsNotNull(rule.Validate(null, 0, null, null));
                Assert.IsNotNull(rule.Validate(null, 1, null, null));
                Assert.IsNull(rule.Validate(null, 2, null, null));
                Assert.IsNotNull(rule.Validate(null, 3, null, null));
                Assert.IsNotNull(rule.Validate(null, 4, null, null));
            }

        }


        [TestFixture]
        public class RuleInterpretation
        {
            [Test]
            public void Simple()
            {
                var rule1 = new RangeRule<int>(null, false, expectedMinimum, expectedMaximum, true, true);
                Assert.IsNotNull(rule1.RuleInterpretation);
                var rule2 = new RangeRule<int>(null, false, expectedMinimum, expectedMaximum, false, false);
                Assert.IsNotNull(rule2.RuleInterpretation);
            }

        }

        
#if (!WindowsCE && !SILVERLIGHT)
        [TestFixture]
        public class GetBaseValidator
        {
            [Test]
            public void NonDateTime()
            {
                var rule = new RangeRule<int>(null, false, expectedMaximum, expectedMinimum, true, true);
                var infoDescriptor = new MockInfoDescriptor(TypePointers.IntTypeHandle, "foo");
                var ruleContext = new RuleContext {Rule = rule, InfoDescriptor = infoDescriptor};
                var list = BaseValidatorGenerator.Strategies.FindStrategy(ruleContext).CreateWebClientValidators(rule, infoDescriptor);
                Assert.IsNotNull(list);
                Assert.AreEqual(1, list.Count);
            }


            [Test]
            public void Unknown()
            {
                var rule = new RangeRule<fooStruct>(null, false, new fooStruct(), new fooStruct(), true, true);
                var infoDescriptor = new MockInfoDescriptor(typeof(fooStruct).TypeHandle, "foo");
                var ruleContext = new RuleContext { Rule = rule, InfoDescriptor = infoDescriptor };
				Assert.IsNull(BaseValidatorGenerator.Strategies.FindStrategy(ruleContext));

            }
            [Test]
            public void Date()
            {
                var expectedMinimum = new DateTime(2007, 1, 1);
                var expectedMaximum = expectedMinimum.AddDays(1);

                var rule = new RangeRule<DateTime>(null, false, expectedMinimum, expectedMaximum, true, true);
                var infoDescriptor = new MockInfoDescriptor(typeof(DateTime).TypeHandle, "foo");
                var ruleContext = new RuleContext { Rule = rule, InfoDescriptor = infoDescriptor };
                var list = BaseValidatorGenerator.Strategies.FindStrategy(ruleContext).CreateWebClientValidators(rule, infoDescriptor);
                Assert.IsNotNull(list);
                Assert.AreEqual(1, list.Count);
            }


            [Test]
            public void AsDateTime()
            {
                var expectedMinimum = new DateTime(2007, 1, 1).AddHours(1);
                var expectedMaximum = expectedMinimum.AddDays(1);

                var rule = new RangeRule<DateTime>(null, false, expectedMinimum, expectedMaximum, true, true);
                var infoDescriptor = new MockInfoDescriptor(typeof(DateTime).TypeHandle, "foo");
                var ruleContext = new RuleContext { Rule = rule, InfoDescriptor = infoDescriptor };
                var list = BaseValidatorGenerator.Strategies.FindStrategy(ruleContext).CreateWebClientValidators(rule, infoDescriptor);
                Assert.IsNull(list);
            }


            [Test]
            public void MaxAsDateTime()
            {
                var expectedMinimum = new DateTime(2007, 1, 1);
                var expectedMaximum = expectedMinimum.AddDays(1).AddHours(1);
                var rule = new RangeRule<DateTime>(null, false, expectedMinimum, expectedMaximum, true, true);
                var infoDescriptor = new MockInfoDescriptor(typeof(DateTime).TypeHandle, "foo");
                var ruleContext = new RuleContext { Rule = rule, InfoDescriptor = infoDescriptor };
                var list = BaseValidatorGenerator.Strategies.FindStrategy(ruleContext).CreateWebClientValidators(rule, infoDescriptor);
                Assert.IsNull(list);
            }


            [Test]
            public void MinAsDateTime()
            {
                var expectedMinimum = new DateTime(2007, 1, 1);
                var expectedMaximum = expectedMinimum.AddDays(1);
                expectedMinimum = expectedMinimum.AddHours(1);
                var rule = new RangeRule<DateTime>(null, false, expectedMinimum, expectedMaximum, true, true);
                var infoDescriptor = new MockInfoDescriptor(typeof(DateTime).TypeHandle, "foo");
                var ruleContext = new RuleContext { Rule = rule, InfoDescriptor = infoDescriptor };
                var list = BaseValidatorGenerator.Strategies.FindStrategy(ruleContext).CreateWebClientValidators(rule, infoDescriptor);
                Assert.IsNull(list);
                //Assert.AreEqual(1, list.Count);
            }

        }
#endif

        [TestFixture]
        public class CheckTypes
        {
            [Test]
            public void Simple()
            {
                var rule1 = new RangeRule<int>(null, false, 0, 10, true, true);
                rule1.CheckType(new MockInfoDescriptor(TypePointers.IntTypeHandle, "foo"));

                var rule2 = new RangeRule<int>(null, false, 0, 10, true, true);
                rule2.CheckType(new MockInfoDescriptor(typeof (int?).TypeHandle, "foo"));
            }


            [Test]
            [ExpectedException(typeof(ArgumentException), ExpectedMessage = "Member 'foo' must be a 'System.Int32' to be used for the ValidationFramework.RangeRule<System.Int32>. Actual Type 'System.String'.\r\nParameter name: value")]
            public void ExceptionInvalidType()
            {
                var rule = new RangeRule<int>(null, false, 0, 10, true, true);
                rule.CheckType(new MockInfoDescriptor(TypePointers.StringTypeHandle, "foo"));
            }
        }



        struct fooStruct : IComparable<fooStruct>, IComparable
        {


            public int CompareTo(fooStruct other)
            {
                throw new NotImplementedException();
            }

            public int CompareTo(object obj)
            {
                throw new NotImplementedException();
            }
        }




    }
}